home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1998 February
/
Macworld (1998-02).dmg
/
Control Strip Modules
/
Debugger Strip
/
debug.c
next >
Wrap
C/C++ Source or Header
|
1995-10-28
|
11KB
|
377 lines
#include "debug.h"
#include <Icons.h>
#include "ControlStrip.h"
#include <Gestalt.h>
/**************
Debugger Strip GH, a simple demonstration of how to write a
control strip module. 11/27/94, version 1.2.1
**
changes:
• added balloon help
• now use a slightly different method to determine if a debugger
is installed.
• Now use the SetupA4 routines, not because I need them here, but
you will need them if you want to use string constants while using
CodeWarrior; without A4 setup, the compiler won't be able to find
the data for declarations like:
Str255 driverName = "\p.AppleCD";
**
In case you can't use the enclosed CodeWarrior project, you should
use this code to compile a code resource of type 'sdev' and resID 0,
and merge it into the enclosed control strip module.
**
This module simply drops into MacsBug when clicked.
Command clicking brings up a menu of ways to drop into Macsbug. You
can add different ways by adding items to the appropriate STR# resources
(id 998 = menu itms and id 999 = debugger strings).
Read the OS 6 Tech note.
On the Develop Bookmark 19 CD there is another example control strip module
called "MacCalender".
ControlStrip.h is now with the Universal headers.
Remember to change the creator for your own modules.
Problems I've noticed:
* SBTrackSlider appears to be broken; it doesn't return the correct value
* SBGetDetachedIndString doesn't necessarily return a null string if the
index is invalid
* Think Reference has incorrect declarations for the icon suite routines
Use the official Apple Icons.h file.
* This module doesn't dehilite if the user drags outside its rect like
it ought to. This is because I need to handle the mouse click manually if I
want to be able to show a menu. .
--glenn howes
grhowes@kagi.com
*****************/
#ifdef __MWERKS__
#include <A4Stuff.h>
#endif
pascal long main (long message, long params, Rect *statusRect, GrafPtr statusPort)
{
long result = 0L;
#ifdef __MWERKS__
long oldA4 = SetCurrentA4(); // needed only if you want to have inline strings
#endif
switch (message)
{
case sdevPeriodicTickle: // idle routine
// result = DoCSPeriodic((MyGlobalHandle) params, statusRect, statusPort);
break;
case sdevInitModule: // check environs, allocate globals
result = DoCSInit(); // return allocated globals handle or -1 for failure
break;
case sdevCloseModule: // release my memory
DoCSClose((MyGlobalHandle) params);
break;
case sdevFeatures: // I want to handle mouseclicks myself, and I support balloon help
result = (1L << sdevWantMouseClicks) | (1L << sdevDontAutoTrack)
| (1L << sdevHasCustomHelp);
break;
case sdevGetDisplayWidth:
result = 16L; // size of a small icon width
break;
case sdevDrawStatus: // draw my icon
DoCSDraw((MyGlobalHandle) params, statusRect, statusPort);
break;
case sdevMouseClick: // the mouse was clicked in my button
result = DoCSClick((MyGlobalHandle) params, statusRect, statusPort);
break;
case sdevSaveSettings: // DoCSClick must have returned a 2 sometime
DoCSSavePrefs((MyGlobalHandle) params);
break;
case sdevShowBalloonHelp:
result = DoCSBalloonHelp((MyGlobalHandle) params, statusRect);
break;
}
#ifdef __MWERKS__
SetA4( oldA4 );
#endif
return (result);
}
long DoCSBalloonHelp(MyGlobalHandle myGlobals, Rect *statusRect)
{
Str255 aString;
SBGetDetachedIndString(aString, (*myGlobals)->utilityStrings, kHelpString);
return (SBShowHelpString(statusRect, aString));
}
/***********
DoCSPeriodic, remember to uncomment the call to this routine in the main routine.
The Control Strip will constantly be calling your module, so be a good
strip citizen. Don't use a periodic routine if you don't need to, and
use a large kTickleLength if your periodic code routine is time consuming
I use 120 (2 seconds)
***********/
long DoCSPeriodic(MyGlobalHandle myGlobals, Rect *statusRect, GrafPtr statusPort)
{
unsigned long ticks, lastTicks;
unsigned long mask = 1L<<31;
ticks = TickCount();
lastTicks = (*myGlobals)->lastTicks;
if (ticks >= lastTicks // either we've waited at least kTickleLength
|| ((lastTicks & mask) && !(ticks & mask)))// or mac was on for 2 years and ticks wrapped (it could happen)
{
(*myGlobals)->lastTicks = ticks + kTickleLength;
// insert your periodic code here
}
return (0L);
}
/******
If I returned a value with the #1 bit set (a 2 for instance) in response to
a sdevPeriodicTickle or sdevMouseClick, I will receive this message
*********/
void DoCSSavePrefs(MyGlobalHandle myGlobals)
{
Str255 aString;
OSErr iErr;
Handle prefH;
if (prefH = NewHandle(sizeof(short)))
{
SBGetDetachedIndString(aString, (*myGlobals)->utilityStrings, kPrefName);
**(short**)prefH = (*myGlobals)->whichString;
iErr = SBSavePreferences(aString, prefH);
DisposeHandle(prefH);
}
}
/********
If the user clicks inside my module's rectangle, I'll get this message.
If my prefererences are changed, I'll return 2, otherwise 0
*********/
long DoCSClick(MyGlobalHandle myGlobals, Rect *statusRect, GrafPtr statusPort)
{
Boolean shiftPressed, commandPressed, inMyRect=true;
Point localPnt;
long retVal = 0L;
short oldIndex, newIndex;
MenuHandle hMenu;
Str255 debugString;
shiftPressed = IsPressed(kShiftKey);
commandPressed = IsPressed(kCommandKey);
if (commandPressed) // present a configuration menu
{
hMenu = MakePrefsMenu(myGlobals);
if (hMenu)
{
oldIndex = (*myGlobals)->whichString;
newIndex = SBTrackPopupMenu(statusRect, hMenu);
if (newIndex && newIndex != oldIndex)
{
(*myGlobals)->whichString = newIndex;
retVal = (1L<< sdevNeedToSave);// set preference changed flag
}
DisposeMenu(hMenu);
}
if (!shiftPressed || !newIndex) return (retVal);
// else execute immediately (inMyRect was initialized to true)
}
else // manually track mouse
{
do
{
GetMouse(&localPnt);
inMyRect = PtInRect(localPnt,statusRect);
}while (StillDown());
}
if (inMyRect)
{
SBGetDetachedIndString(debugString,
(*myGlobals)->debuggerStrings, (*myGlobals)->whichString);
if (debugString[0])
DebugStr(debugString);
else
Debugger();
}
return (retVal);
}
MenuHandle MakePrefsMenu(MyGlobalHandle myGlobals)
{
MenuHandle retVal = 0L;
Str255 menuItem;
Str63 dummy;
short item = 1, numItems;
short **numItemsH;
dummy[0] = 0;
retVal = NewMenu(702,dummy); // arbitrary menu id, no title
if (retVal)
{
numItemsH = (short**) (*myGlobals)->menuStrings;
numItems = **numItemsH; // manually find out how many strings I have
for(item = 1; item<= numItems; item++)
{
SBGetDetachedIndString(menuItem, (*myGlobals)->menuStrings, item);
AppendMenu(retVal,menuItem); // note that the string shouldn't start with a -
// unless you want a grey line
}
if ((*myGlobals)->whichString <= numItems)
SetItemMark(retVal,(*myGlobals)->whichString,sdevMenuItemMark); // the bullet
}
return(retVal);
}
/*
DoCSInit -- returns a handle to my allocated globals or -1 if the environment is
wrong or I couldn't allocate my memory/load my resources
*/
long DoCSInit(void)
{
MyGlobalHandle myH;
OSErr iErr;
Handle iconSuite = 0L;
Handle menuStrings, debugStrings, utilityStrings;
Str255 prefName;
short **whichStringH;
if (HasDebugger()) // is a debugger installed?
{
myH = (MyGlobalHandle) NewHandleClear(sizeof(MyGlobals));
iErr = SBGetDetachIconSuite(&iconSuite, 669, 0x0000FF00L);
menuStrings = GetDetachedStrings(kMenuStrings);
debugStrings = GetDetachedStrings(kDebuggerStrings);
utilityStrings = GetDetachedStrings(kUtilityStrings);
if (myH && iconSuite && menuStrings && debugStrings && utilityStrings)
// was I able to allocate my memory?
{
(*myH)->menuStrings = menuStrings;
(*myH)->debuggerStrings = debugStrings;
(*myH)->utilityStrings = utilityStrings;
(*myH)->iconSuite = iconSuite;
SBGetDetachedIndString(prefName, utilityStrings, kPrefName);
iErr = SBLoadPreferences(prefName, (Handle*) &whichStringH);
if (!iErr && whichStringH)
{
(*myH)->whichString = **whichStringH;
DisposeHandle((Handle)whichStringH);
}
else (*myH)->whichString = 1; // default
return ((long) myH); // return my globals
}
else // failed to allocate all my needed memory
{
if(myH) DisposeHandle((Handle) myH);
if(iconSuite) DisposeIconSuite (iconSuite, true);
if (menuStrings) DisposeHandle(menuStrings);
if (debugStrings) DisposeHandle(debugStrings);
if (utilityStrings) DisposeHandle(utilityStrings);
}
}
return (-1L); // something went wrong, don't install
}
/*
DoCSClose, basically just deallocate all my memory
*/
void DoCSClose(MyGlobalHandle myGlobals)
{
if (myGlobals)
{
DisposeIconSuite ((*myGlobals)->iconSuite, true);
DisposeHandle((*myGlobals)->menuStrings);
DisposeHandle((*myGlobals)->debuggerStrings);
DisposeHandle((*myGlobals)->utilityStrings);
DisposeHandle((Handle) myGlobals);
}
}
/*
DoCSDraw, just draw my icon. Remember that sometimes the rectangle
that gets passed will be narrower than the one expected (if your module
is the last visible module and the strip isn't long enough to draw the
whole thing.
*/
void DoCSDraw(MyGlobalHandle myGlobals, Rect *statusRect, GrafPtr statusPort)
{
OSErr iErr;
short alignment = kAlignAbsoluteCenter; // center up & down , and left & right
long transform = kTransformNone; // no transform
Rect iconRect;
if ((*myGlobals)->iconSuite)
{
iconRect.left = statusRect->left; iconRect.top = statusRect->top;
iconRect.bottom = statusRect->bottom;
iconRect.right = iconRect.left + 16; // I don't want icon squished if the
// status rect is too narrow (rely on clipping)
iErr = PlotIconSuite(&iconRect,alignment,transform,(*myGlobals)->iconSuite);
}
}
/*
As I shouldn't access my module's resource file after initialization, I use
this routine to load in my STR# resources and convert them to regular
(non resource) relocatable blocks
*/
Handle GetDetachedStrings(short id)
{
Handle strH;
strH = Get1Resource('STR#',id);
if (strH)
{
DetachResource(strH);
}
return(strH);
}
/*
IsPressed returns true if the given key is being pressed. I use this to
check the modifier key states
*/
Boolean IsPressed(unsigned short key)
{
unsigned char keyMap[16];
GetKeys((unsigned long *)&keyMap);
return((keyMap[key>>3]>>(key & 7)) & 1);
}
/*
The following is a technical improvement on my original HasDebugger()
routine. This is based on information found in a snippet under the path
sample code/snippets/platforms & tools/debuggerpresence, and also some
info in Think Reference
*/
Boolean HasDebugger(void)
{
char *debugFlagPtr;
short debugFlags;
if (Can32Bit()) // machine is capable of using 32-bit addressing (might be in 24-bit mode)
{
debugFlagPtr = (char *) 0xBFFL; // location of debugger info flags if 32 bit possible
}
else
{
debugFlagPtr = (char *) 0x120L; // location of debugger info flags if 32 bit impossible
}
debugFlags = *debugFlagPtr;
if (debugFlags & 1<<5) // test debugger present flag
return(TRUE);
else
return (FALSE);
}
Boolean Can32Bit(void) // can this machine be placed in 32-bit mode?
{
long addressingMode;
OSErr iErr;
iErr = Gestalt(gestaltAddressingModeAttr, &addressingMode);
if (!iErr && (addressingMode & (1 << gestalt32BitCapable)))
return (TRUE);
else
return (FALSE);
}